#include "getspasswd.h"
// 分割字符串函数
// 输入: 原始字符串，指向前部分的指针，指向后部分的指针
// 返回: 成功找到冒号返回1，否则返回0
int split_string(const char *input, char **front, char **back) {
    // 查找冒号位置
    const char *colon_pos = strchr(input, ':');
    
    if (colon_pos == NULL) {
        // 没有找到冒号
        return 0;
    }
    
    // 计算前部分长度并分配内存
    size_t front_len = colon_pos - input;
    *front = (char *)malloc(front_len + 1);
    if (*front == NULL) {
        perror("内存分配失败");
        return 0;
    }
    strncpy(*front, input, front_len);
    (*front)[front_len] = '\0'; // 添加字符串结束符
    
    // 计算后部分长度并分配内存
    size_t back_len = strlen(colon_pos + 1);
    *back = (char *)malloc(back_len + 1);
    if (*back == NULL) {
        perror("内存分配失败");
        free(*front); // 释放已分配的前部分内存
        return 0;
    }
    strcpy(*back, colon_pos + 1);
    
    return 1;
}

char* extract_password_prefix(const char* encrypted_password) {
    if (encrypted_password == NULL) {
        return NULL;
    }
    
    // 计算字符串中$符号的数量
    int dollar_count = 0;
    const char* p = encrypted_password;
    while (*p != '\0') {
        if (*p == '$') {
            dollar_count++;
        }
        p++;
    }
    
    // 至少需要4个$符号（格式：$id$parameters$salt$hash）
    if (dollar_count < 4) {
        return NULL;
    }
    
    // 找到第三个$符号后的位置（即盐值结束的位置）
    int found = 0;
    p = encrypted_password;
    while (*p != '\0' && found < 3) {
        if (*p == '$') {
            found++;
        }
        p++;
    }
    
    // 找到第四个$符号的位置
    const char* end = p;
    while (*end != '\0' && *end != '$') {
        end++;
    }
    
    // 计算前缀的长度（从开始到第四个$符号）
    size_t prefix_len = end - encrypted_password + 1; // +1 为了包含第四个$
    
    // 分配内存并复制前缀
    char* prefix = (char*)malloc(prefix_len + 1); // +1 用于空字符
    if (prefix == NULL) {
        return NULL;
    }
    
    strncpy(prefix, encrypted_password, prefix_len);
    prefix[prefix_len] = '\0';
    
    return prefix;
}
int check_password(const char *username_and_passwd, char **username_out) {
    char* user_name = NULL;
    char* user_passwd = NULL;
    split_string(username_and_passwd, &user_name, &user_passwd);

    struct spwd* user_info = getspnam(user_name);
    ERROR_CHECK(user_info, NULL, "getspnam");

    char* salt = extract_password_prefix(user_info->sp_pwdp);
    int check = strcmp(crypt(user_passwd, salt), user_info->sp_pwdp);
    printf("check=%d\n", check);

    // 如果认证成功，设置输出参数
    if (check == 0 && username_out != NULL) {
        *username_out = strdup(user_name);
    }

    return check;
}
int send_auth_fail(int netfd){
    train_t train;
    bzero(&train,sizeof(train));
    train.type=AUTH_FAIL;
    train.length=0;
    send(netfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);
    send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    return 0;
}
int send_auth_success(int netfd){
    train_t train;
    bzero(&train,sizeof(train));
    train.type=AUTH_SUCCESS;
    train.length=0;
    send(netfd,&train.type,sizeof(train.type),MSG_NOSIGNAL);
    send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    return 0;
}
int gate(int netfd, char **username_out) {
    train_t train;
    bzero(&train, sizeof(train));
    
    // 接收认证请求
    if (recv(netfd, &train.type, sizeof(train.type), MSG_WAITALL) <= 0) {
        close(netfd);
        return 0;
    }
    
    if (train.type != AUTH_REQUEST) {
        send_auth_fail(netfd);
        close(netfd);
        return 0;
    }
    
    if (recv(netfd, &train.length, sizeof(train.length), MSG_WAITALL) <= 0) {
        close(netfd);
        return 0;
    }
    
    if (recv(netfd, train.value, train.length, MSG_WAITALL) <= 0) {
        close(netfd);
        return 0;
    }
    train.value[train.length] = '\0';
    
    // 解析用户名和密码
    char *username = strtok(train.value, ":");
    char *password = strtok(NULL, ":");
    
    // 检查格式是否正确
    if (username == NULL || password == NULL) {
        send_auth_fail(netfd);
        close(netfd);
        return 0;
    }
    
    // 验证用户名和密码
    char *authenticated_username = NULL;
    if (check_password(train.value, &authenticated_username) != 0) {
        send_auth_fail(netfd);
        close(netfd);
        return 0;
    }
    
    // 认证成功，设置输出参数
    if (username_out != NULL) {
        *username_out = authenticated_username;
    } else {
        free(authenticated_username); // 如果调用者不需要用户名，释放内存
    }
    
    send_auth_success(netfd);
    return 1;
}
